create schema if not exists vit;

create table if not exists vit.houses(
	id serial primary key,
	street text not null,
	number text not null
);

create table if not exists vit.apartments(
	id serial primary key,
	number text not null,
	house_id int,
	foreign key (house_id) references vit.houses(id) on delete restrict on update cascade
);

create table if not exists vit.resource_types(
	name text not null,
	value int not null
);

create table if not exists vit.meters(
	id serial primary key,
	resource_id int not null,
	manufacturer text not null,
	model text not null,
	serial_number text not null,
	verification_interval int not null,
	installation_date date not null,
	dismantling_date date,
	is_first_tariff_in_use bool not null default true,
	is_second_tariff_in_use bool not null default false,
	is_third_tariff_in_use bool not null default false,
	foreign key (resource_id) references vit.resource_types(value) on delete restrict on update cascade
);

create table if not exists vit.meter_values(
	id serial primary key,
	meter_id int not null,
	"d" timestamp not null,
	t1 float,
	t2 float,
	t3 float,
	foreign key (meter_id) references vit.meters(id) on delete restrict on update cascade
);

create table if not exists vit.meter_verification_history(
	id serial primary key,
	meter_id int,
	"d" date not null,
	"to" date not null,
	foreign key (meter_id) references vit.meters(id) on delete restrict on update cascade
);

create table if not exists vit.house_meters(
	id serial primary key,
	house_id int not null,
	meter_id int not null,
	foreign key (meter_id) references vit.meters(id) on delete restrict on update cascade,
	foreign key (house_id) references vit.houses(id) on delete restrict on update cascade
);
 
create table if not exists vit.apartment_meters(
	id serial primary key,
	apartment_id int not null,
	meter_id int not null,
	foreign key (meter_id) references vit.meters(id) on delete restrict on update cascade,
	foreign key (apartment_id) references vit.apartments(id) on delete restrict on update cascade
);

create or replace procedure vit.fill_meter_val_verh(outer_meter_id integer, meter_data jsonb)
as $$
	begin
		-- RAISE NOTICE 'Сейчас house_data = %', (meter_data->'v'->0->'d')::text; 

		if jsonb_typeof(meter_data->'v') = 'array' then
		 insert into vit.meter_values (
				meter_id,
				d,
				t1,
				t2,
				t3
			)
			select outer_meter_id, sub.d, sub.t1, sub.t2, sub.t3 from (select * from jsonb_populate_recordset(
					null::vit.meter_values,
					meter_data->'v'
				)
			) sub;
		end if;

		if jsonb_typeof(meter_data->'vh') = 'array' then
			insert into vit.meter_verification_history(
				meter_id,
				"d",
				"to"
			)
			select outer_meter_id, sub_vh.d, sub_vh.to from (select * from jsonb_populate_recordset(
					null::vit.meter_verification_history,
					meter_data->'vh'
				)
			) sub_vh;
		end if;
	end;
$$ LANGUAGE plpgsql;

create or replace procedure vit.create_meter(meter_data jsonb, out meter_created_id int)
as $$
	begin
		insert into vit.meters (
			resource_id,
			manufacturer,
			model,
			serial_number,
			verification_interval,
			installation_date,
			dismantling_date,
			is_first_tariff_in_use,
			is_second_tariff_in_use,
			is_third_tariff_in_use
		) values (
			(meter_data->>'res')::int,
			meter_data->>'man',
			meter_data->>'mod',
			meter_data->>'sn',
			(meter_data->>'vi')::int,
			(meter_data->>'id')::date,
			(meter_data->>'dd')::date,
			(meter_data->>'t1')::bool,
			(meter_data->>'t2')::bool,
			(meter_data->>'t3')::bool
		) returning id into meter_created_id;

	end;
$$ LANGUAGE plpgsql;


create or replace procedure vit.fill_data()
as $$
	DECLARE
	    house_line_id int;
	begin 
		for house_line_id in select id from public.input_data loop
			declare
				house_data jsonb;
				house_inserted_id int;
				house_apartment_data jsonb;
				apartment_inserted_id int;
				apartment_meter_data jsonb;
				apartment_meter_id int;
				house_meter jsonb;
				house_meter_inserted_id int;
			begin
				select data into house_data from public.input_data where id = house_line_id;

				insert into vit.houses(street, number) values (house_data->'s', house_data->'n')
				returning id into house_inserted_id;

				if jsonb_typeof(house_data->'a') != 'array' then
					CONTINUE;
				end if;

				for house_apartment_data in SELECT * FROM jsonb_array_elements(house_data->'a') loop
					-- RAISE NOTICE 'Сейчас house_data = %', house_data->'s'; 

					insert into vit.apartments (number, house_id)
					values (house_apartment_data->>'n', house_inserted_id)
					returning id into apartment_inserted_id;

					if jsonb_typeof(house_data->'a') != 'array' then
						CONTINUE;
					end if;

					for apartment_meter_data in SELECT * FROM jsonb_array_elements(house_apartment_data->'m') loop
						
						-- =====================
						-- insert into vit.meters (
						-- 	resource_id,
						-- 	manufacturer,
						-- 	model,
						-- 	serial_number,
						-- 	verification_interval,
						-- 	installation_date,
						-- 	dismantling_date,
						-- 	is_first_tariff_in_use,
						-- 	is_second_tariff_in_use,
						-- 	is_third_tariff_in_use
						-- ) values (
						-- 	apartment_meter_data->'res',
						-- 	apartment_meter_data->'man',
						-- 	apartment_meter_data->'mod',
						-- 	apartment_meter_data->'sn',
						-- 	apartment_meter_data->'vi',
						-- 	apartment_meter_data->'id',
						-- 	apartment_meter_data->'dd',
						-- 	apartment_meter_data->'t1',
						-- 	apartment_meter_data->'t2',
						-- 	apartment_meter_data->'t3'
						-- ) returning id into apartment_meter_id;
						-- =====================
						
						call vit.create_meter(apartment_meter_data, apartment_meter_id);

						insert into vit.apartment_meters (apartment_id, meter_id)
						values (apartment_inserted_id, apartment_meter_id);

						call vit.fill_meter_val_verh(apartment_meter_id, apartment_meter_data);
					end loop;
				end loop;

				for house_meter in  SELECT * FROM jsonb_array_elements(house_data->'hm') loop
				
					call vit.create_meter(house_meter, house_meter_inserted_id);
					
					insert into vit.house_meters (house_id, meter_id)
					values (house_inserted_id, house_meter_inserted_id);

					call vit.fill_meter_val_verh(house_meter_inserted_id, house_meter);
				end loop;
				-- RAISE NOTICE 'Сейчас house_data = %', house_data->'s'; 
				-- RAISE NOTICE 'Сейчас number = %', house_data->'n'; 
			end;
		end loop;
	end;
$$ LANGUAGE plpgsql;


CREATE OR REPLACE VIEW vit.values_without_verification AS(
	(
		select
			h.street,
			h.number as house,
			m.manufacturer,
			m.model,
			m.serial_number,
			mv.d as date,
			mv.t1,
			mv.t2,
			mv.t3
		from vit.houses h
		left join vit.apartments ha on ha.house_id = h.id
		left join vit.apartment_meters am on am.apartment_id = ha.id
		left join vit.meters m on m.id = am.meter_id
		left join vit.meter_values mv on mv.meter_id = am.meter_id
		left join vit.meter_verification_history mvh on mvh.meter_id = am.meter_id
		where (mv.d not between mvh.d and mvh."to")
	)
	union 
	(
		select
			h.street,
			h.number as house,
			m.manufacturer,
			m.model,
			m.serial_number,
			mv.d as date,
			mv.t1,
			mv.t2,
			mv.t3
		from vit.houses h
		left join vit.house_meters hm on hm.house_id = h.id
		left join vit.meters m on m.id = hm.meter_id
		left join vit.meter_values mv on mv.meter_id = m.id
		left join vit.meter_verification_history mvh on mvh.meter_id = m.id
		where (mv.d not between mvh.d and mvh."to")
	)
	order by street, house, manufacturer, model, serial_number, date
);


CREATE OR REPLACE VIEW vit.values_bihourly AS (
	(
		select
			h.street,
			h.number as house,
			m.manufacturer,
			m.model,
			m.serial_number,
			mv.d as date,
			mv.t1,
			mv.t2,
			mv.t3
		from (
			select date_trunc('hour', mv_in.d) as hourly, max(mv_in.id) as id from vit.meter_values mv_in
			where extract(hour from mv_in.d)::int % 2 = 0
			group by hourly
		) hourly
		left join vit.meter_values mv on mv.id = hourly.id
		left join vit.meters m on m.id = mv.meter_id
		left join vit.apartment_meters am on am.meter_id = m.id
		left join vit.apartments ha on ha.id = am.apartment_id
		left join vit.houses h on h.id = ha.house_id
	)
	union 
	(
		select
			h.street,
			h.number as house,
			m.manufacturer,
			m.model,
			m.serial_number,
			mv.d as date,
			mv.t1,
			mv.t2,
			mv.t3
		from (
			select date_trunc('hour', mv_in.d) as hourly, max(mv_in.id) as id from vit.meter_values mv_in
			where extract(hour from mv_in.d)::int % 2 = 0
			group by hourly
		) hourly
		left join vit.meter_values mv on mv.id = hourly.id
		left join vit.meters m on m.id = mv.meter_id
		left join vit.house_meters hm on hm.meter_id = m.id
		left join vit.houses h on h.id = hm.house_id
	)
	order by street, house, manufacturer, model, serial_number, date
);

create or replace view vit.individual_consumption_by_resource as (
	(
		select
			h.street,
			h.number as house,
			m.resource_id as resource,
			date_trunc('day', mv.d) as date,
			sum(mv.t1) as t1,
			sum(mv.t2) as t2,
			sum(mv.t3) as t3
		from vit.houses h
		left join vit.apartments ha on ha.house_id = h.id
		left join vit.apartment_meters am on am.apartment_id = ha.id
		left join vit.meters m on m.id = am.meter_id
		left join vit.meter_values mv on mv.meter_id = am.meter_id
		group by street, house, resource, date
	)
	union 
	(
		select
			h.street,
			h.number as house,
			m.resource_id as resource,
			date_trunc('day', mv.d) as date,
			sum(mv.t1) as t1,
			sum(mv.t2) as t2,
			sum(mv.t3) as t3
		from vit.houses h
		left join vit.house_meters hm on hm.house_id = h.id
		left join vit.meters m on m.id = hm.meter_id
		left join vit.meter_values mv on mv.meter_id = m.id
		group by street, house, resource, date
	)
	order by street, house, resource, date
);

create or replace view vit.meter_models as (
	select manufacturer, model, count(*) from vit.meters
	group by manufacturer, model
	order by manufacturer, model
);

create or replace view vit.monthly_consumption as (
	select
		h.street,
		h.number as house,
		case 
			when mv.d isnull then extract(year from hmmv.d)::int
			else extract(year from mv.d)::int
		end as "year",
		case 
			when mv.d isnull then extract(month from hmmv.d)::int
			else extract(month from mv.d)::int
		end as "month",
		case
			when mm.resource_id isnull then hmm.resource_id
			else mm.resource_id
		end as "resource",
		sum(mv.t1) as im_t1,
		sum(mv.t2) as im_t2,
		sum(mv.t3) as im_t3,
		sum(hmmv.t1) as hm_t1,
		sum(hmmv.t2) as hm_t2,
		sum(hmmv.t3) as hm_t3
	from vit.houses h
	left join vit.house_meters hm on hm.house_id = h.id
	left join vit.meters hmm on hmm.id = hm.meter_id
	left join vit.meter_values hmmv on hmmv.meter_id = hmm.id
	left join vit.apartments ha on ha.house_id = h.id
	left join vit.apartment_meters am on am.apartment_id = ha.id
	left join vit.meters mm on mm.id = am.meter_id
	left join vit.meter_values mv on mv.meter_id = am.meter_id
	group by street, house, year, month, resource
	order by street, house, year, month, resource
);


